home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
BBS in a Box 7
/
BBS in a Box - Macintosh - Volume VII (BBS in a Box) (January 1993).iso
/
Files
/
Tele
/
C
/
Comet2.1.3.cpt
/
emlib
/
macro.c
< prev
next >
Wrap
Text File
|
1991-07-25
|
43KB
|
2,013 lines
/*
Copyright Cornell University 1986. All rights are reserved.
macro.c routines handle scanning keys for macro matches,
presenting a dialog for users to associate macros with keys,
and dumping the key macros.
For a list of valid macro codes, see ::include:rcodes.h.
*/
#include <em.h>
#include <net.h>
#include <h19.h>
#include <rcodes.h>
#include <resdefs.h>
#define NEG (-1)
/* each key on the keyboard has a unique name derived from this table,
which associates keycodes & titles */
#define KEYCODES 128
char * keytitle[KEYCODES] = {
"A",
"S",
"D",
"F",
"H",
"G",
"Z",
"X",
"C",
"V",
"?",/* 10 */
"B",
"Q",
"W",
"E",
"R",
"Y",
"T",
"1",
"2",
"3",/* 20 */
"4",
"6",
"5",
"=",
"9",
"7",
"-",
"8",
"0",
"]",/* 30 */
"O",
"U",
"[",
"I",
"P",
"Return",
"L",
"J",
"'",
"K",/* 40 */
";",
"\\",
",",
"/",
"N",
"M",
".",
"Tab",
"Space",
"`",/* 50 */
"Backspace/delete",
"Enter",
"esc",
"?",
"?",
"?",
"?",
"?",
"?",
"?",/* 60 */
"?",
"?",
"?",
"?",
". (KP)",
"* (KP)",
"* (KP)",
"?",
"+ (KP)",
"+ (KP)",/* 70 */
"Clear (KP)",
", (KP)",
"?",
"?",
"/ (KP)",
"Enter (KP)",
"/ (KP)",
"- (KP)",
"?",
"?",/* 80 */
"= (KP)",
"0 (KP)",
"1 (KP)",
"2 (KP)",
"3 (KP)",
"4 (KP)",
"5 (KP)",
"6 (KP)",
"7 (KP)",
"?",/* 90 */
"8 (KP)",
"9 (KP)",
"?",
"?",
"?",
"F5",
"F6",
"F7",
"F3",
"F8", /* 100 */
"F9",
"?",
"F11",
"?",
"F13",
"?",
"F14",
"?",
"F10",
"?", /* 110 */
"F12",
"?",
"F15",
"help",
"home",
"page up",
"X->",
"F4",
"end",
"F2", /* 120 */
"page down",
"F1",
"Left",
"Right",
"Down",
"Up",
"?"
};
/* key macro mapping dialog defines */
#define DIBMKEYEXCEPT 11450
#define DASCKEYEXCEPT 11451
#define DKEYNADA 0 /* do nothing at all */
#define DKEYOK 1 /* OK button */
#define DKEYCANCEL 2 /* cancel button */
#define DKEYPRESS 3 /* do another key */
#define DKEYDESC 4 /* text description of key */
/* skip */
#define DKEYACTION 6 /* action code has been changed */
#define DKEYCODE 7 /* the action code so user can see it */
/* skip */
#define DKEYKILL 9 /* remove key from macro list */
#define DKEYQUIT 10 /* quit this dialog */
#define DKEYHELP 11 /* show help window */
#define DKEYSHOW 12 /* show all the current key macros */
#define DKEYDISPLAY 1000 /* do the actual key display */
/* the range from 14 to MAXBUTACT is associated with buttons which produce the command strings for you */
#define DPF1 14
#define DPFACTS 24
#define DACT1 (DPF1 + DPFACTS)
#define MAXBUTACT 57
#define NUMBUTACTS MAXBUTACT - DACT1
#define ITEXTMACROS 2012
#define ALKEYQUIT 0
/* the list of icon codes -- some command codes can appear as a single icon
in the "Ourcago" character set to ease editing */
#define IPF1 128
#define IPF2 129
#define IPF3 130
#define IPF4 131
#define IPF5 132
#define IPF6 133
#define IPF7 134
#define IPF8 135
#define IPF9 136
#define IPF10 137
#define IPF11 138
#define IPF12 139
#define IPF13 140
#define IPF14 141
#define IPF15 142
#define IPF16 143
#define IPF17 144
#define IPF18 145
#define IPF19 146
#define IPF20 147
#define IPF21 148
#define IPF22 149
#define IPF23 150
#define IPF24 151
#define IPA1 152
#define IPA2 153
#define IPA3 154
#define IENTER 155
#define INEWLINE 156
#define ICLEAR 157
#define IRESET 158
#define IHOME 159
#define ILEFT 160
#define IUP 161
#define IDOWN 162
#define IRIGHT 163
#define ITAB 164
#define IBACKTAB 165
#define IINSERT 166
#define IDELETE 167
#define IERINPUT 168
#define IEREOF 169
#define IBSDEL 170
char * outoftext = "Cannot display text--only 255 characters available";
char * endoftext = "Invalid code at end of entry";
long keyid; /* our unique key id, keymods / keycode / keychar */
short keycode; /* key code */
short keymods; /* key modifiers */
short KDnotshown = TRUE; /* no key selected in key dialog, changes CR response */
short doshow = FALSE; /* show codes for next key */
short macrochanged; /* has a key action sequence been modified? */
char emptytext[2] = { '\000', '\000' };
extern char * malloc();
DialogPtr macrodp;
DialogRecord macrodlog;
/* do dialog to examine and set key macro list action codes */
Handle haction; /* action text is global so KDkeymod can get it */
Handle hdesc; /* various dialog objects */
Handle hnext;
Handle hshow;
extern long memtest();
setkeydialog()
{
Rect rect, showrect; /* rect is garbage, others are used */
Rect nextrect;
short dialnum;
short type;
short item_id;
short count;
short nomacro; /* is there an macro list for the current key? */
Str255 desctext, acttext;
Str255 nextprompt;
char * actptr;
struct token * keyact;
GrafPtr oport;
char temptext[512]; /* big array for action code translation */
short templength;
Rect offnextrect; /* used to move "Press key" off-window */
char windtit[256]; /* temp for window title */
extern Boolean KDkeymod();
nomacro = TRUE;
SetDAFont(OURCHICAGO); /* chicago font with control chars defined */
GetPort(&oport);
dialnum = keydp->ibm_keymode ? DIBMKEYEXCEPT : DASCKEYEXCEPT;
emwdeactivate();
if ((macrodp = GetNewDialog(dialnum, (Ptr) ¯odlog, (WindowPtr) (-1))) == NULL)
return(0);
centerwind(macrodp);
reopenconfig(keydp);
showcursor();
SetCursor(&arrow);
SetPort(macrodp);
GetDItem(macrodp, DKEYPRESS, &type, &hnext, &nextrect);
GetWTitle(keydp->emwindow, &windtit[0]);
SetIText(hnext, &windtit[0]);
/* prompt now appears in key description box... */
GetDItem(macrodp, DKEYDESC, &type, &hdesc, &rect);
GetIText(hdesc, &nextprompt);
GetDItem(macrodp, DKEYSHOW, &type, &hshow, &showrect);
GetDItem(macrodp, DKEYACTION, &type, &haction, &rect);
keyshowprep(&nextprompt);
TEFromScrap();
/* get the current scrap in case it's needed to put into the dialog text */
while (TRUE) {
ModalDialog((ProcPtr) KDkeymod, &item_id);
SetPort(macrodp);
switch (item_id) {
case DKEYNADA:
break;
case DKEYOK: {
struct keyxlist * keyxp;
Handle hkeyres;
/* set key to use action codes user has entered */
if (macrochanged) {
/* get text */
GetIText(haction, &acttext);
if ( (templength = actencode(&acttext, &temptext[0])) == NEG ) {
/* encode into an action list, if bad abort ... */
break;
}
if (templength % sizeof(struct token) ) {
/* should be zero, or we've got a bad code ... abort */
stoperror("Uneven number of codes");
break;
}
/* modify the resource */
/* add a resource when:
1) a document file is open and an macro exists,
but in the appl resource file, so we will ignore it;
2) no macro exists */
if (!nomacro) {
keyxp = keyxptr(keyid);
if (!renewresource(keyxp))
nomacro = TRUE;
else if (keydp->resfid != appresfid &&
appresfid == HomeResFile(keyxp->hkeyact)) {
/* the key exists in the Settings file, override it */
nomacro = TRUE;
}
}
/* KS 8/27/86 */
if (nomacro) {
/* make a new resource */
hkeyres = NewHandle((long) (templength + 4)); /* WARNING TODO should use sizeof keyactlist->keyid rather than hardcoded 4 */
((struct keyactlist *) *hkeyres)->keyid = keyid;
/* set the key id field of the new resource */
keyxp = malloc((unsigned) sizeof(struct keyxlist));
keyxp->hkeyact = hkeyres;
/* set up a link */
keyxp->nextkey = keydp->keyxhead;
keydp->keyxhead = keyxp;
/* make the new link first in line */
}
else {
hkeyres = keyxp->hkeyact;
SetHandleSize(hkeyres, (long) (templength + 4)); /* WARNING TODO should use sizeof keyactlist->keyid rather than hardcoded 4 */
}
keyxp->actlen = templength / sizeof(struct token);
mystrncpy(&((struct keyactlist *) *hkeyres)->act[0], &temptext[0],
templength);
/* copy the new data over to the resource */
if (nomacro) {
/* make a new KEYX resource */
short newid;
newid = UniqueID(keydp->ibm_keymode ? 'KEYI' : 'KEYX');
AddResource(hkeyres, keydp->ibm_keymode ? 'KEYI' : 'KEYX',
newid, &desctext);
}
/* write out the resource */
HNoPurge(hkeyres);
ChangedResource(hkeyres);
if (nomacro)
UpdateResFile(keydp->resfid);
else
UpdateResFile(HomeResFile(hkeyres));
if (ResError())
error("Key resource save failed");
DetachResource(hkeyres);
}
keyshowprep(&nextprompt);
break;
}
case DKEYSHOW: {
keyxdump(OURCHICAGO, 12);
break;
}
case DKEYDISPLAY: {
/* do the display for a key combination */
/* unhighlite "Press Key" */
#ifdef KEYPRESSCONTROL
HiliteControl(hnext, 0);
#else
/* SetIText(hnext, "\P"); now in hdesc... */
#endif
/* give the key a name */
namekey(desctext.text, keycode, keymods);
desctext.length = strlen(desctext.text);
SetIText(hdesc, &desctext);
if ( ((keyact = keyxfind(keyid, &count)) != NULL) ) {
/* if key in macro list producing action keys, set action text */
/* TODO is the length restriction assoc. with Str255 acceptable for actions? */
char * textend;
int length;
for ( textend = acttext.text + 254, actptr = acttext.text;
count--; keyact++) {
/* copy text to pascal Str255 */
if ( (length = actdecode(actptr, textend, keyact, TRUE)) == NEG)
/* error decoding--should alert that at end? */
break;
else
actptr += length;
}
acttext.length = actptr - acttext.text;
SetIText(haction, &acttext);
onditem(macrodp, DKEYKILL);
nomacro = FALSE;
}
else {
/* no macro yet exists */
SetIText(haction, emptytext);
nomacro = TRUE;
}
KDnotshown = FALSE;
macrochanged = FALSE;
onditem(macrodp, DKEYCANCEL);
break;
}
case DKEYCANCEL: {
/* do alert to see if cancel ok? */
keyshowprep(&nextprompt);
break;
}
case DKEYACTION: {
if (!macrochanged) {
offditem(macrodp, DKEYQUIT);
onditem(macrodp, DKEYOK);
}
macrochanged = TRUE;
break;
}
case DKEYKILL: {
if (keyxkill(keyxptr(keyid))) {
/* no such key in list */
error("Key not in macro list");
}
keyshowprep(&nextprompt);
break;
}
case DKEYQUIT: {
SetPort(oport);
ZeroScrap();
TEToScrap();
/* copy the TE scrap to the Scrap */
CloseDialog(macrodp);
SetDAFont(systemFont);
closeconfig(keydp);
return(0);
}
case DKEYHELP: {
helpwindow(ITEXTMACROS, geneva, 9);
break;
}
default: {
if (KDnotshown)
error("You need to press a key-combination before you can enter macro buttons");
else
ibmacts(item_id);
break;
}
}
}
}
pascal Boolean
KDkeymod(dptr, devt, item)
DialogPtr dptr;
EventRecord * devt;
short * item;
{
short nkeycode; /* key code */
bkrd_service();
if (devt->what == keyDown) {
nkeycode = (devt->message & 0xff00) >> 8;
if (doshow) {
/* the event is the key we want to display */
keymods = devt->modifiers; /* global for key text */
keycode = nkeycode;
/* derive the keyid from modifier << 16 + message */
keyid = devt->modifiers;
keyid <<= 16;
keyid |= (devt->message & 0xffff);
*item = DKEYDISPLAY;
doshow = FALSE;
return(TRUE);
}
if (KDnotshown) {
if ( (short) (devt->message & 0xff) == CR) {
/* use Return to signal a Show */
*item = DKEYSHOW;
return(TRUE);
}
else {
/* we're not accepting keyed input now */
*item = DKEYCODE;
/* any item that will be ignored will do */
return(TRUE);
}
}
if (!(devt->modifiers & shiftKey) && !(devt->modifiers & cmdKey)
&& ((devt->modifiers & optionKey && !(devt->modifiers & ctrlKey))
|| (devt->modifiers & ctrlKey && !(devt->modifiers & optionKey)))
) {
/* the Control or Option key is down all by itself */
/* make a control char */
char contchar;
contchar = (char) (devt->message & 0xff);
if (!makecontrol(&contchar, nkeycode)) {
/* interpret as a control key */
return(TRUE);
}
*item = DKEYACTION; /* show we saw a key entered */
/* we courageously insert the char ourselves, since TE/Dialog won't reproduce correctly */
TEDelete(macrodlog.textH);
/* kill select range as in standard */
TEInsert(&contchar, (long) 1, macrodlog.textH);
return(TRUE);
}
#define MACROEDIT
#ifdef MACROEDIT
if (devt->modifiers & cmdKey) {
/* do Cut Copy and Paste? */
char thechar;
thechar = devt->message & 0xff;
switch (thechar) {
case 'x': {
TECut(macrodlog.textH);
break;
}
case 'c': {
TECopy(macrodlog.textH);
break;
}
case 'v': {
TEPaste(macrodlog.textH);
break;
}
case '.': {
/* cancel setting the key */
*item = DKEYCANCEL;
return(TRUE);
}
}
*item = DKEYACTION; /* show we saw a key entered */
return(TRUE);
}
#endif
/* TODO add test to distinguish CR & do a show button ? */
}
else if (devt->what == mouseDown && !KDnotshown) {
/* pull down menus to insert codes if doing input and in menu area */
short code;
long menucode;
WindowPtr whichWindow;
code = FindWindow(pass(devt->where), &whichWindow);
if (code == inMenuBar) {
menucode = MenuSelect(pass(devt->where));
}
}
return(FALSE);
}
/* this routine returns a pointer to a keyname table entry */
char nullstring[] = "Unknown Key";
char *
keyname(keycode)
unsigned short keycode;
{
if (keycode >= KEYCODES) {
return(nullstring);
}
return(keytitle[keycode]);
}
/* Get all KEYX resources, which contain a keyid followed by a series of
action codes, and place them into an array of keyid/char pointers
a macro must always have an action handle!
*/
keyxinit()
{
short numkeyx; /* number of macro entries in list of keys */
short count;
long keysize;
Handle keyhand;
struct keyxlist * keyxp;
struct keyxlist * prevkeyxp;
numkeyx = Count1Resources(emdp->ibm_keymode ? 'KEYI' : 'KEYX');
if (numkeyx == 0) {
/* no macros exist, terminate list */
emdp->keyxhead = NULL;
return(0);
}
emdp->keyxhead = keyxp = malloc((unsigned) sizeof(struct keyxlist));
if (emdp->keyxhead == NULL)
return(-1);
for (count = 1; count <= numkeyx; count++) {
keyxp->hkeyact = Get1IndResource(emdp->ibm_keymode ? 'KEYI' : 'KEYX', count);
if (keyxp->hkeyact == NULL)
continue;
DetachResource(keyxp->hkeyact);
/* detach the resource so it's not seen by other windows loading
macros ... */
keyxp->actlen = ((short) GetHandleSize(keyxp->hkeyact) - 4) / sizeof(struct token);
/* TODO should use sizeof keyactlist->keyid rather than hardcoded 4 */
if (count < numkeyx) {
keyxp->nextkey = malloc((unsigned) sizeof(struct keyxlist));
/* allocate next keyxlist struct and set current key pointer to it */
if (keyxp->nextkey == NULL) {
/* give up if we're running out of memory */
break;
}
prevkeyxp = keyxp;
keyxp = keyxp->nextkey;
}
}
keyxp->nextkey = NULL;
/* terminate the list */
if (keyxp->hkeyact == NULL) {
/* couldn't manage to get a resource for the last malloc */
free(keyxp);
if (keyxp == emdp->keyxhead)
/* no macros at all */
emdp->keyxhead = NULL;
else
prevkeyxp->nextkey = NULL;
/* fix the link before to reflect no more in q */
}
return(0);
}
/* This routine returns a pointer to the action sequence associated with a key
if no action sequence exists, it returns NULL
*/
struct keyxlist *
keyxptr(keyid)
long keyid;
{
long keyxid;
struct keyxlist * keyxp;
for (keyxp = keydp->keyxhead; keyxp != NULL; keyxp = keyxp->nextkey) {
keyxid = ((struct keyactlist *) (*keyxp->hkeyact))->keyid;
if (keyxid == keyid) {
/* we've got a match, return pointer to macro struct */
return((struct keyxlist *) keyxp);
}
}
return(NULL);
/* no match */
}
/* TODO should use keyxptr not keyid */
struct token *
keyxfind(keyid, actcount)
long keyid;
short * actcount;
{
long keyxid;
struct keyxlist * keyxp;
struct token * tokep;
for (keyxp = keydp->keyxhead; keyxp != NULL; keyxp = keyxp->nextkey) {
keyxid = ((struct keyactlist *) (*(keyxp->hkeyact)))->keyid;
if (keyxid == keyid) {
/* we've got a match, return count and pointer to action */
*actcount = keyxp->actlen;
tokep = &((struct keyactlist *) *(keyxp->hkeyact))->act[0];
return(tokep);
}
}
return(NULL);
/* no match */
}
/* release the current batch of key resources */
keyxrelease()
{
struct keyxlist * keyxp, * oldxp;
for (keyxp = emdp->keyxhead; keyxp != NULL; ) {
/* go through list releasing all */
DisposHandle(keyxp->hkeyact);
oldxp = keyxp;
keyxp = keyxp->nextkey;
free(oldxp);
}
emdp->keyxhead = NULL;
}
/* remove a key macro entry from the linked list,
and remove the resource from the resource file
*/
char * keyresfail = "Key resource kill failed";
keyxkill(keyp)
struct keyxlist * keyp;
{
struct keyxlist * killnext;
short homekeyres;
if (keyp != NULL) {
/* delete resource */
if (renewresource(keyp)) {
homekeyres = HomeResFile(keyp->hkeyact);
RmveResource(keyp->hkeyact);
UpdateResFile(homekeyres);
if (ResError())
error(keyresfail);
}
DisposHandle(keyp->hkeyact);
if ( (killnext = keyp->nextkey) != NULL) {
/* we're in the front or middle of the list, delete the
list entry by moving *next* entry up and freeing *it* */
keyp->actlen = keyp->nextkey->actlen;
keyp->hkeyact = keyp->nextkey->hkeyact;
keyp->nextkey = keyp->nextkey->nextkey;
free(killnext);
}
else {
/* we're at the end of the list */
if ( (killnext = keydp->keyxhead) == keyp) {
/* we're at the front too! */
keydp->keyxhead = NULL;
free(killnext);
}
else {
/* go through the list of macros until previous link */
for (; killnext->nextkey != keyp; killnext = killnext->nextkey)
;
killnext->nextkey = NULL;
/* terminate the list */
free(keyp);
/* kill the entry */
}
}
return(0);
}
return(NEG);
/* no match */
}
char thisistext[] = "Keys in the macro list:\r\r";
char moretext[] = "\rClick for more...";
char endtext[] = "\rEnd of list, click to exit";
#define DUMPWIND 1111
#define XTEXT 500
keyxdump(font, fontsize)
short font;
short fontsize;
{
long length;
char thetext[XTEXT];
char spaces[8];
EventRecord anevent;
TEHandle texthand;
WindowPtr helpwind;
GrafPtr oldport;
Rect bounds;
struct keyxlist * keyxp;
long keyxid;
short dkeycode, modifiers;
char * actptr;
char * textend;
struct token * keyact;
int count;
emwdeactivate();
if ( (helpwind = GetNewWindow(DUMPWIND, (Ptr) NULL, (WindowPtr) (-1)) ) == NULL)
return(-1);
centerwind(helpwind);
strcpy(&spaces[0], " ");
GetPort(&oldport);
SetPort(helpwind);
bounds.top = 6;
bounds.left = 6;
bounds.bottom = thePort->portRect.bottom - 6;
bounds.right = thePort->portRect.right - 6;
texthand = TENew(&bounds, &bounds);
(*texthand)->txFont = font;
(*texthand)->txSize = fontsize;
TESetSelect( (long) 0, (long) (*texthand)->teLength, texthand);
TEInsert(thisistext, (long) strlen(thisistext), texthand);
for (keyxp = keydp->keyxhead; keyxp != NULL; keyxp = keyxp->nextkey) {
keyxid = ((struct keyactlist *) (*keyxp->hkeyact))->keyid;
modifiers = ((keyxid >> 16) & 0xffff);
dkeycode = (keyxid & 0xffff) >> 8;
/* give the key a name */
TEInsert(&spaces[0], (long) strlen(spaces), texthand);
namekey(thetext, dkeycode, modifiers);
TEInsert(&thetext[0], (long) strlen(thetext), texthand);
TEInsert("--", (long) 2, texthand);
/* now dump the codes for it */
count = keyxp->actlen;
keyact = &((struct keyactlist *) (*keyxp->hkeyact))->act[0];
for (textend = thetext + XTEXT, actptr = &thetext[0]; count--; keyact++) {
if ( (length = actdecode(actptr, textend, keyact, TRUE)) == NEG)
/* error decoding--should alert that at end? */
break;
else
actptr += length;
}
length = actptr - &thetext[0];
if (length + (*texthand)->teLength > 32000) {
error("Text too long to display");
break;
}
if (! memtest(length, "to dump key macros"))
/* out of memory */
break;
TEInsert(&thetext[0], (long) length, texthand);
TEKey(CR, texthand);
if ((*texthand)->selRect.top > bounds.bottom - (4 * fontsize)) {
/* at bottom of window */
TEInsert(moretext, (long) strlen(moretext), texthand);
while (!GetNextEvent(mDownMask, &anevent)) {
/* wait till a mouseDown event occurs to exit, unless a key is hit */
SystemTask(); /* keep this if/until we use WaitNextEvent */
bkrd_service();
if (EventAvail(keyDownMask, &anevent))
/* don't take keystrokes off the queue */
break;
}
TESetSelect( (long) 0, (long) (*texthand)->teLength, texthand);
TEDelete(texthand);
}
}
TEInsert(endtext, (long) strlen(endtext), texthand);
while (!GetNextEvent(mDownMask, &anevent)) {
/* wait till a mouseDown event occurs to exit, unless a key is hit */
SystemTask(); /* keep this if/until we use WaitNextEvent */
bkrd_service();
if (EventAvail(keyDownMask, &anevent))
/* don't take keystrokes off the queue */
break;
}
SetPort(oldport);
TEDispose(texthand);
DisposeWindow(helpwind);
}
#define FIRSTCHAR 0x00
#define LASTCHAR 0x7f
/* decode an action sequence into text with ! marking commands & \ prefixing
hex or decimal numbers
returns an int--the length of the new text
*/
actdecode(textp, textend, theact, commandfont)
unsigned char * textp;
char * textend;
struct token * theact;
int commandfont;
/* assume the font has Command symbols so not all chars > 127 available */
{
register unsigned char thechar;
short command;
char * startp;
short numbered; /* display entry numerically */
startp = textp;
if ( (textp + 1) >= textend) {
error(outoftext);
return(NEG);
}
command = FALSE;
numbered = FALSE;
switch (theact->class) {
case RSLT_ASCI: {
/* leave out the RSLT_ASCI "space" command code in the text */
break;
}
case RSLT_DELAY:
case RSLT_LOOP:
case RSLT_MATCH:
case RSLT_SEL1:
case RSLT_SEL2:
case RSLT_SEL3:
case RSLT_SEL4:
case RSLT_WIND:
case RSLT_XCURS:
case RSLT_YCURS: {
/* use numbers for the entry description--fall through */
*textp++ = '!';
*textp++ = theact->class;
numbered = TRUE;
break;
}
case RSLT_PFKY: {
if (!commandfont) {
/* always use command chars for the entry description--fall through */
*textp++ = '!';
*textp++ = theact->class;
command = TRUE;
break;
}
if ((theact->entry > PF24 && theact->entry <= PF36)) {
/* use numbers for numbered pf keys above 24--fall through */
numbered = TRUE;
}
else {
/* use character button "icons" to represent */
if (theact->entry >= PF1 && theact->entry <= PF24) {
*textp++ = theact->entry + 127;
return(1);
}
else switch(theact->entry) {
case PA1: {
*textp++ = IPA1;
return(1);
}
case PA2: {
*textp++ = IPA2;
return(1);
}
case PA3: {
*textp++ = IPA3;
return(1);
}
case ENTER: {
*textp++ = IENTER;
return(1);
}
case CLEAR: {
*textp++ = ICLEAR;
return(1);
}
}
/* else no icon for code */
/* put out a '!' before the command */
*textp++ = '!';
*textp++ = theact->class;
command = TRUE;
break;
}
}
case RSLT_MVCR: {
if (!commandfont) {
/* always use command chars for the entry description--fall through */
*textp++ = '!';
*textp++ = theact->class;
command = TRUE;
break;
}
/* use the iconic representation */
switch (theact->entry) {
case LEFT_ARROW: {
*textp++ = ILEFT;
return(1);
}
case DOWN_ARROW : {
*textp++ = IDOWN;
return(1);
}
case UP_ARROW: {
*textp++ = IUP;
return(1);
}
case RIGHT_ARROW: {
*textp++ = IRIGHT;
return(1);
}
case HOME: {
*textp++ = IHOME;
return(1);
}
case TAB_FWD: {
*textp++ = ITAB;
return(1);
}
case BACK_TAB: {
*textp++ = IBACKTAB;
return(1);
}
case NEW_LINE: {
*textp++ = INEWLINE;
return(1);
}
}
/* else no icon for code */
/* put out a '!' before the command */
*textp++ = '!';
*textp++ = theact->class;
command = TRUE;
break;
}
case RSLT_LCAC: {
if (!commandfont) {
/* always use command chars for the entry description--fall through */
*textp++ = '!';
*textp++ = theact->class;
command = TRUE;
break;
}
/* use icons for local actions */
switch(theact->entry) {
case INSRT: {
*textp++ = IINSERT;
return(1);
}
case DEL_CHAR: {
*textp++ = IDELETE;
return(1);
}
case ERASE_EOF: {
*textp++ = IEREOF;
return(1);
}
case INPUT_ERASE: {
*textp++ = IERINPUT;
return(1);
}
case BACKSP_DEL: {
*textp++ = IBSDEL;
return(1);
}
case RESET: {
*textp++ = IRESET;
return(1);
}
}
/* else no icon for code */
/* put out a '!' before the command */
*textp++ = '!';
*textp++ = theact->class;
command = TRUE;
break;
}
default: {
/* put out a '!' before the command */
*textp++ = '!';
*textp++ = theact->class;
/* since classes are recognizable chars, no problem decoding */
command = TRUE;
break;
}
}
thechar = theact->entry;
if ( !numbered && thechar >= FIRSTCHAR
&& (commandfont ? thechar <= LASTCHAR : TRUE)
) {
/* ordinary character with extended set, show it */
if (thechar == '\\') {
/* add an escape to an escape char */
if ( (textp + 1) >= textend) {
error(outoftext);
return(NEG);
}
*textp++ = thechar;
*textp++ = thechar;
return(textp - startp);
}
if (!command && thechar == '!') {
/* add an escape to an escape char UNLESS we're in a command sequence */
if ( (textp + 1) >= textend) {
error(outoftext);
return(NEG);
}
*textp++ = thechar;
*textp++ = thechar;
return(textp - startp);
}
/* else */
if (textp >= textend) {
error(outoftext);
return(NEG);
}
*textp++ = thechar;
}
else {
/* make a decimal string */
if ( (textp + 4) > textend) {
error(outoftext);
return(NEG);
}
*textp++ = '\\';
/* was
sprintf(textp, "%3d", thechar);
textp += 3;
no leading zeroes included!
*/
dectrans(textp, thechar);
textp += 3;
}
return(textp - startp);
}
/* this routine converts the text from the dialog from ! commands
and \000 decimal codes to plain tokens */
actencode(text255, textp)
Str255 * text255;
char * textp;
{
unsigned char * srcp;
unsigned char * destp;
unsigned char * endp;
unsigned char thechar;
for (srcp = text255->text, destp = textp, endp = text255->text + text255->length;
srcp < endp; destp++) {
switch ((thechar = *srcp++)) {
case '\\': {
/* hex number encountered */
*destp++ = RSLT_ASCI;
if (*srcp == '\\') {
/* this is an escaped escape char, make a '\' */
if (srcp < endp)
*destp = *srcp++;
break;
}
else if (decdecode(srcp, destp, endp)){
/* bad decimal code or length, position text cursor */
selbadtext(srcp - text255->text, 3);
return(NEG);
}
srcp += 3;
/* skip the three chars that have just been decoded */
break;
}
case '!': {
/* copy 2 literal command bytes */
if (*srcp == '!') {
/* 2 !'s: literal '!', not a command */
if (srcp < endp) {
*destp++ = RSLT_ASCI;
*destp = *srcp++;
}
else {
error(endoftext);
return(NEG);
}
break;
}
/* do the first command byte */
if (*srcp == '\\') {
/* a decimal digit follows */
if (decdecode(++srcp, destp, endp)){
selbadtext(srcp - text255->text, 3);
return(NEG);
}
srcp += 3;
}
else {
/* an ordinary byte length command field follows */
if (srcp < endp)
*destp = *srcp++;
else {
error(endoftext);
return(NEG);
}
}
destp++;
/* do the second command byte */
if (*srcp == '\\') {
/* a decimal digit follows */
if (decdecode(++srcp, destp, endp)) {
selbadtext(srcp - text255->text, 3);
return(NEG);
}
srcp += 3;
}
else {
if (srcp < endp)
*destp = *srcp++;
else {
error(endoftext);
return(NEG);
}
}
break;
}
/* and now we have a slew of iconic representations... */
case IPF1:
case IPF2:
case IPF3:
case IPF4:
case IPF5:
case IPF6:
case IPF7:
case IPF8:
case IPF9:
case IPF10:
case IPF11:
case IPF12:
case IPF13:
case IPF14:
case IPF15:
case IPF16:
case IPF17:
case IPF18:
case IPF19:
case IPF20:
case IPF21:
case IPF22:
case IPF23:
case IPF24: {
/* iconic PF keys */
*destp++ = RSLT_PFKY;
*destp = thechar - 127; /* from 128 -> 1 */
break;
}
case IPA1: {
*destp++ = RSLT_PFKY;
*destp = PA1;
break;
}
case IPA2: {
*destp++ = RSLT_PFKY;
*destp = PA2;
break;
}
case IPA3: {
*destp++ = RSLT_PFKY;
*destp = PA3;
break;
}
case IENTER: {
*destp++ = RSLT_PFKY;
*destp = ENTER;
break;
}
case INEWLINE: {
*destp++ = RSLT_MVCR;
*destp = NEW_LINE;
break;
}
case ICLEAR: {
*destp++ = RSLT_PFKY;
*destp = CLEAR;
break;
}
case IRESET: {
*destp++ = RSLT_LCAC;
*destp = RESET;
break;
}
case IHOME: {
*destp++ = RSLT_MVCR;
*destp = HOME;
break;
}
case ILEFT: {
*destp++ = RSLT_MVCR;
*destp = LEFT_ARROW;
break;
}
case IUP: {
*destp++ = RSLT_MVCR;
*destp = UP_ARROW;
break;
}
case IDOWN: {
*destp++ = RSLT_MVCR;
*destp = DOWN_ARROW;
break;
}
case IRIGHT: {
*destp++ = RSLT_MVCR;
*destp = RIGHT_ARROW;
break;
}
case ITAB: {
*destp++ = RSLT_MVCR;
*destp = TAB_FWD;
break;
}
case IBACKTAB: {
*destp++ = RSLT_MVCR;
*destp = BACK_TAB;
break;
}
case IINSERT: {
*destp++ = RSLT_LCAC;
*destp = INSRT;
break;
}
case IDELETE: {
*destp++ = RSLT_LCAC;
*destp = DEL_CHAR;
break;
}
case IBSDEL: {
*destp++ = RSLT_LCAC;
*destp = BACKSP_DEL;
break;
}
case IERINPUT: {
*destp++ = RSLT_LCAC;
*destp = INPUT_ERASE;
break;
}
case IEREOF: {
*destp++ = RSLT_LCAC;
*destp = ERASE_EOF;
break;
}
default: {
/* ordinary character found, add proper action code prefix */
#ifdef MAGICCR
/* not such a good idea due to modem relationships... */
if (keydp->ibm_keymode && (thechar == CR)) {
/* translate CR to Enter in ibm_keymode */
*destp++ = RSLT_PFKY;
*destp = ENTER;
}
else
#endif
{
*destp++ = RSLT_ASCI;
*destp = thechar;
}
break;
}
}
#ifdef VERIFY
if (tokenverify((struct token *) destp - 1))
/* check the token */
return(NEG);
#endif
}
return(destp - textp);
}
/* a version of strncpy that respects NULS and treats them as equals! */
/* LIBERATE THE NUL SET! */
/* NUL is BEAUTIFUL! */
mystrncpy(dest, source, length)
char * dest;
char * source;
short length;
{
length++;
while (--length) {
*dest++ = *source++;
}
}
char
mkcontrol(thechar)
char thechar;
{
switch (thechar) {
case '-':
case '_': {
/* make a US */
return(0x1f);
}
case '6':
case '^': {
/* make an RS */
return(0x1e);
}
case '2':
case '@': {
/* make a NUL */
return(NUL);
}
case '/':
case '?': {
/* make a DEL */
return(DEL);
}
case BS: {
if (keydp->ba_bs)
/* convert to delete */
return(DEL);
else
return(BS);
}
default: {
if ( (thechar >= 'a' && thechar <= 'z')
|| (thechar >= '[' && thechar <= '_') )
return( (thechar &= 0x1f) );
else
return(NEG);
}
}
}
decval(strp, strlength)
register unsigned char * strp;
int strlength;
{
register unsigned char * endp;
int theval;
int placeval;
int place;
endp = strp + strlength;
place = 1;
for (theval = 0; --endp >= strp; place *= 10) {
/* calculate the number from the right to the left */
if ( (*endp >= '0') && (*endp <= '9') ) {
/* straightforward decimal number */
placeval = *endp - '0';
}
else {
error("Bad Decimal code found--\nnn needed (n = 0-9)");
return(NEG);
}
theval += placeval * place;
}
return(theval);
}
/* decodes a 3 character decimal string if enough src left, placing result in *destp */
decdecode(srcp, destp, endp)
char * srcp;
char * destp;
char * endp;
{
if (srcp + 2 < endp ) {
/* not at end of text */
int dechold;
if ( (dechold = decval(srcp, 3) ) == NEG) {
/* bad dec code found */
return(NEG);
}
else if (dechold < 0 || dechold > 255) {
/* too large for char, size of entry */
error("Decimal code must be less than \256");
return(NEG);
}
*destp = dechold;
return(0);
}
else {
error(endoftext);
return(NEG);
}
}
buthilite(therect)
Rect * therect;
{
Rect cprect;
cprect.top = therect->top;
cprect.left = therect->left;
cprect.bottom = therect->bottom;
cprect.right = therect->right;
PenSize(3, 3);
InsetRect(&cprect, -4, -4);
FrameRoundRect(&cprect, 16, 16);
PenSize(1, 1);
}
onditem(dptr, theitem)
DialogPtr dptr;
short theitem;
{
short type;
Handle hitem;
Rect box;
GetDItem(dptr, theitem, &type, &hitem, &box);
HiliteControl(hitem, 0);
}
offditem(dptr, theitem)
DialogPtr dptr;
short theitem;
{
short type;
Handle hitem;
Rect box;
GetDItem(dptr, theitem, &type, &hitem, &box);
HiliteControl(hitem, 255);
}
togglemacros()
{
keydp->dokeymacros = !keydp->dokeymacros;
getcontext(keydp); /* set window */
if (keydp->dokeymacros)
showmacroflag();
else
clrmacroflag();
}
namekey(strp, keycode, modifiers)
char * strp;
short keycode;
short modifiers;
{
sprintf(strp, "%s%s%s%s%s%s %s",
!(modifiers & btnState) ? "Alt" : "" , /* mouse down, alt state */
modifiers & alphaLock ? "CapsLock" : "" ,
modifiers & shiftKey ? " Shift" : "",
modifiers & optionKey ? " Option" : "" ,
modifiers & cmdKey ? " Command" : "" ,
modifiers & ctrlKey ? " Control" : "" ,
keyname(keycode)
);
}
char buttab[NUMBUTACTS] = {
IENTER,
INEWLINE,
IPA1,
IPA2,
IPA3,
ICLEAR,
IRESET,
IHOME,
IINSERT,
IDELETE,
IERINPUT,
IEREOF,
ILEFT,
IUP,
IDOWN,
IRIGHT,
ITAB,
IBACKTAB,
IBSDEL
};
/* post a string of events that wind up in the text window */
ibmacts(butid)
int butid;
{
register char * butstr;
if (butid >= MAXBUTACT)
return(NEG);
if (butid < DACT1) {
putkeyevt((char) (butid - DPF1 + 128));
return();
}
putkeyevt(buttab[butid - DACT1]);
}
putkeyevt(thechar)
char thechar;
{
long keymess;
PostEvent(keyDown, (long) thechar);
}
selbadtext(start, count)
int start;
int count;
{
SelIText(macrodp, DKEYACTION, (short) start, (short) (start + count));
}
/* silly routine to convert numeric char to decimal character representation w/ leading zeroes */
dectrans(thep, thechar)
char * thep;
unsigned char thechar;
{
int remainder;
*thep++ = thechar / 100 + '0';
remainder = thechar % 100;
*thep++ = (remainder / 10) + '0';
remainder = remainder % 10;
*thep++ = remainder + '0';
}
/* set things up to get a key to show */
keyshowprep(theprompt)
Str255 * theprompt;
{
KDnotshown = TRUE;
doshow = TRUE;
macrochanged = FALSE;
SetIText(hdesc, emptytext);
SetIText(haction, emptytext);
#ifdef KEYPRESSCONTROL
HiliteControl(hnext, 1); /* Press Key control */
#else
SetIText(hdesc, theprompt);
#endif
offditem(macrodp, DKEYOK);
offditem(macrodp, DKEYCANCEL);
offditem(macrodp, DKEYKILL);
onditem(macrodp, DKEYQUIT);
}
/* get back the resource for a given key */
renewresource(keyxp)
struct keyxlist * keyxp;
{
long keyxid;
short dkeycode, modifiers;
char thetext[255];
/* get the resource back again to delete it from the resource file */
keyxid = ((struct keyactlist *) (*keyxp->hkeyact))->keyid;
DisposHandle(keyxp->hkeyact);
/* drop the current detached copy */
modifiers = ((keyxid >> 16) & 0xffff);
dkeycode = (keyxid & 0xffff) >> 8;
namekey(&thetext[0], dkeycode, modifiers);
ctop(&thetext[0]);
keyxp->hkeyact = GetNamedResource(keydp->ibm_keymode ? 'KEYI' : 'KEYX', &thetext[0]);
if (keyxp->hkeyact == NULL) {
return(FALSE);
}
return(TRUE);
}
/* run a dialog to set a macro object */
Handle setmacro(macrotype, macroid, macroname)
unsigned long macrotype; /* resource type i.e. 'CONN' */
short macroid; /* resource # */
char * macroname; /* user level name for the object */
{
Rect rect, nextrect, showrect; /* rect is garbage, others are used */
short dialnum;
short type;
short item_id;
short count;
short nomacro; /* is there an macro list for the current key? */
Str255 desctext, acttext, nextprompt;
char * actptr;
struct token * macrop;
GrafPtr oport;
char temptext[512]; /* big array for action code translation */
short templength;
Rect offnextrect; /* used to move "Press key" off-window */
Handle hmacro;
short quitdialog = FALSE;
char windtit[256]; /* temp for window title */
extern Boolean Dsetmacro();
nomacro = TRUE;
SetDAFont(OURCHICAGO); /* chicago font with control chars defined */
GetPort(&oport);
dialnum = keydp->ibm_keymode ? DIBMKEYEXCEPT : DASCKEYEXCEPT;
reopenconfig(keydp);
hmacro = Get1Resource(macrotype, macroid);
if ((macrodp = GetNewDialog(dialnum, (Ptr) ¯odlog, (WindowPtr) (-1))) == NULL) {
closeconfig(keydp);
return(hmacro);
}
emwdeactivate();
centerwind(macrodp);
showcursor();
SetCursor(&arrow);
SetPort(macrodp);
GetDItem(macrodp, DKEYPRESS, &type, &hnext, &nextrect);
GetWTitle(keydp->emwindow, &windtit[0]);
SetIText(hnext, &windtit[0]);
GetDItem(macrodp, DKEYDESC, &type, &hdesc, &rect);
GetDItem(macrodp, DKEYSHOW, &type, &hshow, &showrect);
GetDItem(macrodp, DKEYACTION, &type, &haction, &rect);
/* do the display for the macro */
/* set the macro's user name */
ctop(macroname);
SetIText(hdesc, macroname);
if ( (hmacro != NULL) ) {
/* if key in macro list producing action keys, set action text */
/* TODO is the length restriction assoc. with Str255 acceptable for actions? */
char * textend;
int length;
HLock(hmacro);
macrop = (struct token *) (*hmacro + 4);
count = (GetHandleSize(hmacro) - 4) / 2;
for ( textend = acttext.text + 254, actptr = acttext.text;
count--; macrop++) {
/* copy text to pascal Str255 */
if ( (length = actdecode(actptr, textend, macrop, TRUE)) == NEG)
/* error decoding--should alert that at end? */
break;
else
actptr += length;
}
acttext.length = actptr - acttext.text;
SetIText(haction, &acttext);
onditem(macrodp, DKEYKILL);
nomacro = FALSE;
HUnlock(hmacro);
}
else {
/* no macro yet exists */
SetIText(haction, emptytext);
offditem(macrodp, DKEYKILL);
nomacro = TRUE;
}
macrochanged = FALSE;
offditem(macrodp, DKEYSHOW);
offditem(macrodp, DKEYQUIT);
onditem(macrodp, DKEYHELP);
onditem(macrodp, DKEYCANCEL);
onditem(macrodp, DKEYOK);
TEFromScrap();
/* get the current scrap in case it's needed to put into the dialog text */
while (TRUE) {
ModalDialog((ProcPtr) Dsetmacro, &item_id);
SetPort(macrodp);
switch (item_id) {
case DKEYNADA: {
break;
}
case DKEYCANCEL: {
/* do alert to see if cancel ok? */
quitdialog = TRUE;
break;
}
case DKEYOK: {
/* set macro object to use action codes user has entered */
if (macrochanged) {
/* get text */
GetIText(haction, &acttext);
if ( (templength = actencode(&acttext, &temptext[0])) == NEG ) {
/* encode into an action list, if bad abort ... */
break;
}
if (templength % sizeof(struct token) ) {
/* should be zero, or we've got a bad code ... abort */
stoperror("Uneven number of codes");
break;
}
/* modify the resource */
/* add a resource whenno macro exists */
if (nomacro) {
/* make a new resource */
hmacro = NewHandle((long) (templength + 4));
((struct keyactlist *) *hmacro)->keyid = 0;
/* set the key id field of the new macro resource to 0*/
}
else {
SetHandleSize(hmacro, (long) (templength + 4));
}
mystrncpy(&((struct keyactlist *) *hmacro)->act[0], &temptext[0],
templength);
/* copy the new data over to the resource */
if (nomacro) {
/* make a new resource */
AddResource(hmacro, macrotype, macroid, macroname);
}
/* write out the resource */
HNoPurge(hmacro);
ChangedResource(hmacro);
UpdateResFile(keydp->resfid);
if (ResError())
error("Macro resource save failed");
}
quitdialog = TRUE;
break;
}
case DKEYKILL: {
RmveResource(hmacro);
UpdateResFile(keydp->resfid);
if (ResError())
error("Can't delete macro resource");
DisposHandle(hmacro);
hmacro = NULL;
quitdialog = TRUE;
break;
}
case DKEYACTION: {
if (!macrochanged) {
offditem(macrodp, DKEYQUIT);
onditem(macrodp, DKEYOK);
}
macrochanged = TRUE;
break;
}
case DKEYHELP: {
helpwindow(ITEXTMACROS, geneva, 9);
break;
}
default: {
ibmacts(item_id);
break;
}
}
if (quitdialog)
break;
}
SetPort(oport);
ZeroScrap();
TEToScrap();
/* copy the TE scrap to the Scrap */
ptoc(macroname);
CloseDialog(macrodp);
SetDAFont(systemFont);
DetachResource(hmacro);
closeconfig(keydp);
return(hmacro);
}
pascal Boolean
Dsetmacro(dptr, devt, item)
DialogPtr dptr;
EventRecord * devt;
short * item;
{
short nkeycode; /* key code */
bkrd_service();
if (devt->what == keyDown) {
nkeycode = (devt->message & 0xff00) >> 8;
if (!(devt->modifiers & shiftKey) && !(devt->modifiers & cmdKey)
&& ((devt->modifiers & optionKey && !(devt->modifiers & ctrlKey))
|| (devt->modifiers & ctrlKey && !(devt->modifiers & optionKey)))
) {
/* the Control or Option key is down all by itself */
/* make a control char */
char contchar;
contchar = (char) (devt->message & 0xff);
if (!makecontrol(&contchar, nkeycode)) {
/* interpret as a control key */
return(TRUE);
}
*item = DKEYACTION; /* show we saw a key entered */
/* we courageously insert the char ourselves, since TE/Dialog won't reproduce correctly */
TEDelete(macrodlog.textH);
/* kill select range as in standard */
TEInsert(&contchar, (long) 1, macrodlog.textH);
return(TRUE);
}
#define MACROEDIT
#ifdef MACROEDIT
if (devt->modifiers & cmdKey) {
/* do Cut Copy and Paste? */
char thechar;
thechar = devt->message & 0xff;
switch (thechar) {
case 'x': {
TECut(macrodlog.textH);
break;
}
case 'c': {
TECopy(macrodlog.textH);
break;
}
case 'v': {
TEPaste(macrodlog.textH);
break;
}
case '.': {
/* cancel setting the key */
*item = DKEYCANCEL;
return(TRUE);
}
}
*item = DKEYACTION; /* show we saw a key entered */
return(TRUE);
}
#endif
/* TODO add test to distinguish CR & do a show button ? */
}
else if (devt->what == mouseDown && !KDnotshown) {
/* pull down menus to insert codes if doing input and in menu area */
short code;
long menucode;
WindowPtr whichWindow;
code = FindWindow(pass(devt->where), &whichWindow);
if (code == inMenuBar) {
menucode = MenuSelect(pass(devt->where));
}
}
return(FALSE);
}